package fastcsv.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

public class ArgumentsParser {

	/**
	 * whether parsing is successful.
	 */
	public boolean isvalid = false;

	/**
	 * The size of arguments.
	 */
	public int length = 0;

	/**
	 * key:String, value: ArrayList<String> hashmap
	 */
	public HashMap<String, ArrayList<String>> map = new HashMap<>();
	/**
	 * Stores arguments with no key, such as "/data" in the command "ls /data"
	 */
	public ArrayList<String> nokeyValues = new ArrayList<String>();

	/**
	 * For test.
	 * @param args
	 */
	public static void main(String args[]) {
		// for test
		args = "-encoding utf8 -t -print 5 3 -d ./bin -cp /Users/hao/servlet-api.jar ./src/*.java".split(" ");
		args = "encoding utf8 -t -print 5 3 -d ./bin -cp /Users/hao/servlet-api.jar ./src/*.java".split(" ");
		ArgumentsParser ap = ArgumentsParser.parse(args);

		if (ap == null) {
			System.out.println("Parsing failed.");
			return;
		}

		System.out.println("---------- Info ---------");
		for (String key : ap.getKeys()) {
			String[] al = ap.getValues(key);
			System.out.printf("key = %s, value count = %d, content = [%s]\n", key, al.length, String.join(", ", al));
		}

		System.out.println("---------- No-key Values ---------");
		for (String key : ap.nokeyValues) {
			System.out.printf("value: %s\n", key);
		}

		System.out.println("---------- Key Existance Check ---------");
		System.out.println("hasKey(\"encoding\"): " + ap.hasKey("encoding"));
		System.out.println("hasKey(\"dp\"): " + ap.hasKey("dp"));

		System.out.println("---------- Get Values ---------");
		for (String path : ap.getValues("cp"))
			System.out.println("cp: " + path);
	}

	/**
	 * Get the values of a key.
	 * 
	 * @param key A key.
	 * @return A string array.
	 */
	public String[] getValues(String key) {
		if (!hasKey(key))
			return new String[0];
		ArrayList<String> value_list = map.get(key);
		String[] values = new String[value_list.size()];
		for (int i = 0; i < value_list.size(); i++)
			values[i] = value_list.get(i);
		return values;
	}

	/**
	 * Initialize from a string array. If successful, isvalide turns to true, else
	 * false.
	 * 
	 * @param args
	 */
	public static ArgumentsParser parse(String[] args) {
		ArgumentsParser ap = new ArgumentsParser();
		try {
			ArrayList<String> arglist = new ArrayList<String>();
			int pos = 0;
			ap.nokeyValues.clear();
			for (int i = 0; i < args.length; i++) {
				if (!args[i].startsWith("-")) {
					ap.nokeyValues.add(args[i]);
					pos++;
				} else
					break;
			}

			for (int i = pos; i < args.length; i++)
				arglist.add(args[i]);

			for (String arg : arglist) {
				// case 1: non-hyphen started arguments.
				if (!arg.startsWith("-"))
					continue;

				// case 2: tags with 0 argument values.
				String key = arg.substring(1);
				int arg_index = arglist.indexOf(arg);
				if (arg_index == arglist.size() - 1 || arglist.get(arg_index + 1).startsWith("-")) {
					ap.map.put(key, new ArrayList<String>());
					continue;
				}

				// case 3: key with 1 or more argument values
				ArrayList<String> argstrs = new ArrayList<>();
				int i = 1;
				while (arg_index + i != arglist.size() && !arglist.get(arg_index + i).startsWith("-")) {
					argstrs.add(arglist.get(arg_index + i));
					i++;
				}
				ap.map.put(arg.replace("-", ""), argstrs);
			}
			ap.isvalid = true;
		} catch (Exception ex) {
			ap.isvalid = false;
		}
		
		return ap;
	}

	public boolean hasKey(String key) {
		return key != null && key.length() > 0 && map.containsKey(key);
	}

	/**
	 * Return argument keys.
	 * 
	 * @return
	 */
	public Set<String> getKeys() {
		return map.keySet();
	}

	public String getString(String keyName) {
		return getString(keyName, null);
	}

	public String getString(String keyName, String defaultValue) {
		return this.hasKey(keyName) ? map.get(keyName).get(0) : defaultValue;
	}

	public String[] getStrings(String argumentName) {
		if (map.containsKey(argumentName))
			return map.get(argumentName).toArray(new String[0]);
		else
			return new String[0];
	}

	public int getInt(String keyName, int defaultValue) {
		int retValue = 0;
		try {
			if (hasKey(keyName))
				retValue = Integer.parseInt(map.get(keyName).get(0));
		} catch (Exception ex) {
			retValue = defaultValue;
		}
		return retValue;
	}
}
